﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Utilities
{
    public class Graph
    {
        public List<GraphElement> Elements { get; set; }
        public List<Pair<GraphPin, GraphPin>> Links { get; set; }

        public Graph()
        {
            Elements = new List<GraphElement>();
            Links = new List<Pair<GraphPin, GraphPin>>();
        }

        public void Add(GraphElement element)
        {
            if (Elements.Contains(element))
                throw new Exception("This element is already in the graph");
            Elements.Add(element);
        }
        public void Link(GraphPin inputPin, GraphPin outputPin)
        {
            if (!Elements.Contains(e => e.OutputPins.Contains(inputPin)) || !Elements.Contains(e => e.InputPins.Contains(outputPin)))
                throw new Exception("At least one pins is not present in the graph");
            if (Links.Contains(l => l.Value1 == inputPin && l.Value2 == outputPin))
                throw new Exception("A link with these two pins is already registred");

            Links.Add(new Pair<GraphPin, GraphPin>(inputPin, outputPin));
            inputPin.OutgoingLinks.Add(outputPin);
            outputPin.IncomingLinks.Add(inputPin);
        }
    }

    public class Graph<T>
    {
        public GraphElementCollection<T> Elements { get; set; }
        public List<Pair<GraphPin<T>, GraphPin<T>>> Links { get; set; }

        public Graph()
        {
            Elements = new GraphElementCollection<T>();
            Links = new List<Pair<GraphPin<T>, GraphPin<T>>>();
        }

        public void Add(GraphElement<T> element)
        {
            if (Elements.Contains(element))
                throw new Exception("This element is already in the graph");
            Elements.Add(element);
        }
        public virtual void Add(string name, T value)
        {
            Elements.Add(new GraphElement<T>(name, value));
        }

        public void Link(GraphPin<T> outputPin, GraphPin<T> inputPin)
        {
            if (!Elements.Contains(e => e.OutputPins.Contains(outputPin)) || !Elements.Contains(e => e.InputPins.Contains(inputPin)))
                throw new Exception("At least one pins is not present in the graph");
            if (Links.Contains(l => l.Value1 == outputPin && l.Value2 == inputPin))
                throw new Exception("A link with these two pins is already registred");

            Links.Add(new Pair<GraphPin<T>,GraphPin<T>>(outputPin, inputPin));
            inputPin.IncomingLinks.Add(outputPin);
            outputPin.OutgoingLinks.Add(inputPin);
        }
        public void Link(string outputElementName, string outputPinName, string inputElementName, string inputPinName)
        {
            GraphElement<T> outputElement = Elements[outputElementName];
            GraphPin<T> outputPin = outputElement.OutputPins[outputPinName];

            GraphElement<T> inputElement = Elements[inputElementName];
            GraphPin<T> inputPin = inputElement.InputPins[inputPinName];

            Link(outputPin, inputPin);
        }
    }
}
